package mirkofrancuski.battleship.gui;

import java.util.Random;

import mirkofrancuski.battleship.R;
import mirkofrancuski.battleship.game.Board;
import mirkofrancuski.battleship.game.Coordinates;
import mirkofrancuski.battleship.game.Board.Direction;
import mirkofrancuski.battleship.gui.DrawableShip.DrawableState;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.Toast;

public class PlacementBoard extends GameBoard {

	private String DEBUG_TAG = "DEBUG PlacementBoard";

	private boolean rotateShip;
	private DrawableShip mShipSelected;

	private GestureDetector gestures;

	private class GestureListener extends
			GestureDetector.SimpleOnGestureListener implements
			GestureDetector.OnDoubleTapListener {

		@Override
		public boolean onDoubleTap(MotionEvent e) {
			Log.v(DEBUG_TAG, "onDoubleTap");
			rotateShip = true;
			return false;
		}

		@Override
		public boolean onDown(MotionEvent e) {
			Log.v(DEBUG_TAG, "onDown");
			selectShip(calcCoord(e.getX(), e.getY()));
			if (mShipSelected == null)
				return false;
			if (rotateShip) {
				rotateSelecedShip(calcCoord(e.getX(), e.getY()));
			}

			return true;
		}

		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2,
				final float velocityX, final float velocityY) {
			Log.v(DEBUG_TAG, "onFling");
			return true;
		}

		@Override
		public boolean onScroll(MotionEvent e1, MotionEvent e2,
				float distanceX, float distanceY) {
			Log.v(DEBUG_TAG, "onScroll");
			mShipSelected.onMove(-distanceX, -distanceY);
			updateSelectedShip(calcCoord(e2.getX(), e2.getY()));
			return true;

		}
	}

	public PlacementBoard(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);

		gestures = new GestureDetector(context, new GestureListener());

		Coordinates coord = new Coordinates();
		for (int i = 0; i < mShips.length; i++) {
			coord.vertical = 0;
			coord.horizontal = i;

			mShips[i].setBegining(coord);
			mShips[i].place();
			board.placeShip(mShips[i].ship);
		}

		mShipSelected = null;
		rotateShip = false;

	}

	public PlacementBoard(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		setMeasuredDimension(mCellWidth * 12, mCellWidth * 12);
	}

	@Override
	protected void onDraw(Canvas canvas) {

		for (DrawableShip ship : mShips) {
			ship.draw(canvas);
			Log.d(DEBUG_TAG, "Matrix: " + ship.getTranslate().toShortString());
		}
		Log.d(DEBUG_TAG, "Board: " + board.toString());
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {

		boolean returnValue = gestures.onTouchEvent(event);

		if (event.getActionMasked() == MotionEvent.ACTION_UP) {
			Log.v(DEBUG_TAG, "ACTION_UP");
			unselectShip(calcCoord(event.getX(), event.getY()));
			returnValue = true;
		}

		return returnValue;
	}

	private int differnceX = 0;
	private int differnceY = 0;
	private Coordinates currCoordinates = null;

	private void selectShip(Coordinates touchCoordinates) {
		if (!board.isInBounds(touchCoordinates)
				|| board.isEmpty(touchCoordinates))
			return;

		Log.v(DEBUG_TAG, "select");
		currCoordinates = new Coordinates(touchCoordinates);

		mShipSelected = selectDrawableShip(board.getCell(touchCoordinates));
		mShipSelected.setState(DrawableState.PLACEABLE);
		Coordinates oldBegining = mShipSelected.ship.start;

		Log.d(DEBUG_TAG, "oldBegin: " + oldBegining.toString());

		board.pickUpShip(mShipSelected.ship);

		differnceY = oldBegining.horizontal - touchCoordinates.horizontal;
		differnceX = oldBegining.vertical - touchCoordinates.vertical;

		Log.d(DEBUG_TAG, "Ship: " + mShipSelected.ship);
		Log.d(DEBUG_TAG, "diff(" + differnceX + "," + differnceY + ")");
		invalidate();
	}

	private void unselectShip(Coordinates touchCoordinates) {
		Log.v(DEBUG_TAG, "unselect");
		touchCoordinates.horizontal += differnceY;
		touchCoordinates.vertical += differnceX;

		Log.d(DEBUG_TAG, "newBegin: " + touchCoordinates.toString());
		Log.d(DEBUG_TAG, "Ship: " + mShipSelected.ship);
		Log.d(DEBUG_TAG, "diff(" + differnceY + "," + differnceX + ")");

		if (!board.isPlaceable(touchCoordinates, mShipSelected.ship.direction,
				mShipSelected.ship.shipCell)) {

			if (rotateShip)
				mShipSelected.rotate();
			Toast.makeText(getContext(), R.string.toast_error_placment,
					Toast.LENGTH_LONG).show();
		} else
			mShipSelected.setBegining(touchCoordinates);

		board.placeShip(mShipSelected.ship);
		mShipSelected.place();
		mShipSelected.setState(DrawableState.NORMAL);
		mShipSelected = null;
		rotateShip = false;
		invalidate();
	}

	private void updateSelectedShip(Coordinates touchCoordinates) {
		if (currCoordinates == touchCoordinates)
			return;

		currCoordinates = new Coordinates(touchCoordinates);

		Log.v(DEBUG_TAG, "update");
		touchCoordinates.horizontal += differnceY;
		touchCoordinates.vertical += differnceX;

		if (board.isPlaceable(touchCoordinates, mShipSelected.ship.direction,
				mShipSelected.ship.shipCell))
			mShipSelected.setState(DrawableState.PLACEABLE);
		else
			mShipSelected.setState(DrawableState.UNPLACEABLE);

		Log.d(DEBUG_TAG, "newBegin: " + touchCoordinates.toString());
		Log.d(DEBUG_TAG, "currCoord: " + currCoordinates.toString());
		Log.d(DEBUG_TAG, "state = " + mShipSelected.getState());

		invalidate();
	}

	private void rotateSelecedShip(Coordinates touchCoordinates) {
		Log.v(DEBUG_TAG, "rotate");

		int tmp = differnceY;
		differnceY = differnceX;
		differnceX = tmp;

		mShipSelected.rotate();

		Log.d(DEBUG_TAG, "Ship: " + mShipSelected.ship);
		Log.d(DEBUG_TAG, "diff(" + differnceY + "," + differnceX + ")");

	}

	public void randomPlacement() {
		Log.v(DEBUG_TAG, "randomPlacement");
		board.clear();
		Random randomGenerator = new Random();
		Direction oldDirection;
		Coordinates coord = new Coordinates();
		for (int i = 0; i < mShips.length; i++) {
			Log.d(DEBUG_TAG, "i: " + i);

			oldDirection = mShips[i].ship.direction;

			coord.horizontal = randomGenerator.nextInt(Board.BOARD_SIZE);
			coord.vertical = randomGenerator.nextInt(Board.BOARD_SIZE);

			mShips[i].setBegining(coord);
			mShips[i].ship.direction = Direction.values()[randomGenerator
					.nextInt(2)];

			Log.d(DEBUG_TAG, "Coord: " + coord);
			Log.d(DEBUG_TAG,
					"Direction: " + mShips[i].ship.direction.toString());

			Log.d(DEBUG_TAG, "Ship: " + mShips[i].ship.toString());

			if (!board.placeShip(mShips[i].ship)) {
				mShips[i].ship.direction = oldDirection;
				i--;
				continue;
			}
			Log.d(DEBUG_TAG, "Board:\n" + board.toString());

			if (oldDirection != mShips[i].ship.direction) {
				mShips[i].ship.direction = oldDirection;
				mShips[i].rotate();
			}
			mShips[i].place();
		}
		invalidate();
	}

}
